home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #49 (Oct 89) / SC #49.sit / Driver Code / Pdriver.a < prev    next >
Text File  |  1988-01-12  |  15KB  |  568 lines

  1.                 TITLE            'Pump driver'
  2.                 BLANKS            ON
  3.                 CASE            ON
  4.                 String            Pascal
  5.                 Machine            MC68020
  6.  
  7.                 PRINT            OFF
  8.                 INCLUDE         'Traps.a'
  9.                 INCLUDE         'ToolEqu.a'
  10.                 INCLUDE         'QuickEqu.a'
  11.                 INCLUDE         'SysEqu.a'
  12.                 INCLUDE         'SysErr.a'
  13.                 INCLUDE         'TimeEqu.a'
  14.                 INCLUDE         'Quickdraw.inc'
  15.                 INCLUDE         'GNEGlobals.inc'
  16.                 INCLUDE         'PumpErrs.inc'
  17.                 LOAD            'ProgStrucMacs.d'
  18.                 LOAD            'FlowCtlMacs.d'
  19.                 LOAD            'DRVRStruct.d'
  20.                 PRINT            ON
  21.                 
  22.                 IMPORT            HexSet,IntegerSet,AskFormat,RespondToRead
  23.                 IMPORT            SerialComplete,TimeOutInstall
  24.                 
  25. ParamBlockSize        equ            108
  26. ActionOffset        equ            csParam
  27. RequestOffset        equ            csParam+2
  28. InfoOffset            equ            csParam+4
  29. DCEPtr                equ            csParam+6
  30.  
  31. IntegerFmt            equ            0
  32. HexFmt                equ            1
  33.  
  34. Ask                    equ            0
  35. Set                    equ            1
  36.  
  37. S_request            equ            0
  38. R_request            equ            1
  39. V_request            equ            2
  40. I_request            equ            3
  41.  
  42. baud2400            equ            46
  43. stop10                equ            16384
  44. noParity            equ            0
  45. data8                equ            3072
  46.  
  47. EnabledFlags        equ            (1<<dStatEnable) + (1<<dCtlEnable) + (1<<dNeedTime)
  48. EventMask            equ            1<<app1Evt                        ; Handle only driver events
  49.  
  50. Owned                equ            %1100000000000000
  51.  
  52. DrvrStorage            EQU            A3
  53. StringAddress        EQU            A1
  54.  
  55. DStore                Record        0
  56. WriteUnit            DS.W        1
  57. ReadUnit            DS.W        1
  58. TimeCount            DS.L        1
  59. KillBlock            DS.L        1
  60. KillTask            DS.L        1
  61. IncomingLength        DS.B        1
  62. IncomingString        DS.B        9
  63.                     Align        2
  64. TableOffset            equ            *
  65. TableLen            DS.W        1
  66. Table                DS.W        5
  67.                     ENDR
  68.  
  69. IOString            Record        0
  70. OutgoingString        DS.B        8
  71. ReadBuffer            DS.B        1
  72.                     Align        2
  73. StringAllocation    equ            *
  74.                     ENDR
  75.  
  76.  
  77. EvRecord            Record        0
  78. myEvent             DS.L        EventRecord     ; Current event info
  79.                     ENDR
  80.  
  81.             DRVRStart    DRVREntry
  82.             
  83.     DRVRBegin    Save=A2-A4/D1-D2,with=(DStore,IOString,GNEGlobals,EvRecord);
  84.  
  85.     DC.B    EnabledFlags
  86.     DC.B    0                                    ; Lower byte is unused
  87.     DC.W    7*60                                ; periodic actions every 7 seconds
  88.     DC.W    EventMask
  89.     DC.W    0                                    ; No menu for this accessory
  90.  
  91. ;            org            drvrOpen
  92.             
  93.     DC.W    DRVROpen                        ; Open routine
  94.     DC.W    DRVRPrime                        ; Prime
  95.     DC.W    DRVRControl                        ; Control
  96.     DC.W    DRVRStatus                        ; Status
  97.     DC.W    DRVRClose                         ; Close
  98.  
  99. DRVRTitle
  100.     DC.B    'PumpDriver'                         ; Driver Name
  101.     ALIGN    2                                    ; Word align
  102.     
  103.  
  104. DRVROpen        DRVREnter
  105.  
  106.                 MOVE.L            A1,A2
  107.  
  108. *  Load the pump request table from the resource fork
  109.  
  110. ResHandle        equ        A4
  111.  
  112.                 Call    _GetNamedResource:L ( #'PDDF':L , #'Table':A ),ResHandle:L
  113.                 EXG                A0,ResHandle
  114.                 _HLock
  115.                 _GetHandleSize
  116.                 If#        D0    LT.L    #0    Then.S
  117.                     MOVE.W            #openErr,ioResult(ResHandle)
  118.                     Return
  119.                 EndIf#
  120.                 EXG                A0,ResHandle
  121.                 MOVE.L            D0,D1
  122.                 
  123.                 MOVE.L            A0,-(SP)
  124.  
  125. *  Get a new handle to put the Driver globals and the pump request table into
  126.  
  127.                 MOVE.L            A1,-(SP)
  128.                 ADD.L            #TableOffset,D0
  129.                 _NewHandle ,clear
  130.                 _HLock
  131.                 MOVE.L            A0,dCtlStorage(A2)
  132.                 MOVE.L            (A0),A1
  133.                 MOVE.L            A1,DrvrStorage
  134.                 ADD.L            #TableOffset,A1
  135.                 MOVE.L            (ResHandle),A0
  136.                 MOVE.L            D1,D0
  137.                 _BlockMove
  138.                 Call    _ReleaseResource ( ResHandle:L )
  139.                 MOVE.L            (SP)+,A1
  140.  
  141. *  Open the serial drivers and set them up for the pump                
  142.                 
  143.                 MOVE.L            #ParamBlockSize,D0
  144.                 _NewPtr ,clear
  145.                 LEA                #'.AOUT',A2
  146.                 MOVE.L            A2,ioNamePtr(A0)
  147.                 MOVE.B            #fsWrPerm,ioPermssn(A0)
  148.                 _Open
  149.                 
  150.                 If#    D0    NE.W    #noErr    Then.S
  151.                     MOVE.L            (SP)+,A0
  152.                     MOVE.W            #openErr,ioResult(A0)
  153.                     Return
  154.                 EndIf#
  155.                 
  156.                 MOVE.W            ioRefNum(A0),WriteUnit(DrvrStorage)
  157.  
  158. *  Set the output port for 2400 baud, 1 stop, no parity, eight bit communication
  159.  
  160. PortSetting        equ            baud2400+stop10+noParity+data8
  161.                 
  162.                 MOVE.W            #PortSetting,csParam(A0)
  163.                 MOVE.W            #8,csCode(A0)
  164.                 _Control
  165.                 
  166. *  Open the input port
  167.                 
  168.                 LEA                #'.AIN',A2
  169.                 MOVE.L            A2,ioNamePtr(A0)
  170.                 MOVE.B            #fsRdPerm,ioPermssn(A0)
  171.                 _Open
  172.                 
  173.                 If#    D0    NE.W    #noErr    Then.S
  174.                     MOVE.L            (SP)+,A0
  175.                     MOVE.W            #openErr,ioResult(A0)
  176.                     Return
  177.                 EndIf#
  178.                 
  179.                 MOVE.W            ioRefNum(A0),ReadUnit(DrvrStorage)
  180.  
  181. *  Set the input port for 2400 baud, 1 stop, no parity, eight bit communication
  182.  
  183.                 MOVE.W            #PortSetting,csParam(A0)
  184.                 MOVE.W            #8,csCode(A0)
  185.                 _Control
  186.                 _KillIO
  187.                 _DisposPtr
  188.                 
  189. *  Set up a parameter block for the serial IO timeout function. The pointer is stored in the
  190. *  Driver private storage. Also insert a task into the time manager queue which performs the
  191. *  IO timeout function.
  192.  
  193.                 MOVE.L            #ParamBlockSize,D0
  194.                 _NewPtr ,clear
  195.                 MOVE.L            A0,KillBlock(DrvrStorage)
  196.                 MOVE.L            #1500,TimeCount(DrvrStorage)
  197.                 MOVE.L            #tmQSize,D0
  198.                 _NewPtr
  199.                 MOVE.L            A0,KillTask(DrvrStorage)
  200.                 Call    TimeOutInstall ( A0:L , KillBlock(DrvrStorage):L )
  201.  
  202. *  Add a routine to the GNEFilter chain to handle calling the pump driver with appropriate
  203. *  driver events.  The filter rouitne is stored in a resource of type 'GNEF',
  204. *  named 'GNEFilter', and is accessed by name so that multiple drivers can
  205. *  use the same filter. The resource must be locked & nonpurgeable, but should
  206. *  not be preloaded. The driver gets a handle to the resource, dereferences
  207. *  it, and checks the Drvr_num field. If the value there is zero, then we
  208. *  store the value in the system global JGNEFilter in the longword above
  209. *  the entry point for our GNE filter, and place the GNE filter pointer in
  210. *  JGNEFilter. The address of our GNE filter is found by adding the offset
  211. *  found in the first word of the resource to the dereferenced handle. We
  212. *  also allocate a pointer for the filter's use and store it at the offset
  213. *  Control_Ptr. Whether or not the value of Drvr_num was zero, we then check
  214. *  to make sure the driver reference number is not already in the list, and if
  215. *  not, increment Drvr_num and add the driver's reference number to the list
  216. *  of cooperating drivers. 
  217.  
  218.                 Call    _GetNamedResource:L ( #'GNEF':L , #'GNEFilter':A ),A2
  219.                 CMPA            #0,A2
  220.                 If#    NE    Then.S
  221.                     MOVE.L            (A2),A2
  222.                     MOVE.W            Drvr_num(A2),D1
  223.                     If#    D1 EQ.W    #0    Then.S
  224.                         MOVE.W            (A2),D0
  225.                         LEA                (A2,D0.W),A3
  226.                         MOVE.L            JGNEFilter,-4(A3)
  227.                         MOVE.L            A3,JGNEFilter
  228.                         MOVE.L            #ParamBlockSize,D0
  229.                         _NewPtr ,clear
  230.                         MOVE.L            A0,Control_Ptr(A2)
  231.                     EndIf#
  232.                     MOVE.W            dCtlRefNum(A1),D2
  233.                     If#    D1    LE    #entry_slots    Then.S
  234.                         For#    D1 DownTo    #1 Do.S
  235.                             If#    Drvr_num(A2,D1.W*2) EQ.W D2 Then.S
  236.                                 GoTo#.S    DuplicateDrvr
  237.                             EndIf#
  238.                         EndF#
  239.                             
  240.                         ADD.W            #1,Drvr_num(A2)
  241.                         MOVE.W            Drvr_num(A2),D1
  242.                         MOVE.W            D2,Drvr_num(A2,D1.W*2)
  243.                     Else#.S
  244.                     
  245. *  Get the Resource ID for the driver to calculate the ID of owned Alert (sub ID 0)
  246.  
  247.                         LEA            DRVREntry,A0
  248.                         _RecoverHandle
  249.                         LINK            A6,#-12
  250.                         Call    _GetResInfo ( A0:L , (A6):A , 4(A6):A , 8(A6):L )
  251.                         MOVE.W    (A6),D2
  252.                         UNLK            A6
  253.                         MULU            #32,D2
  254.                         ADD.W            #Owned,D2
  255.                         Call    _CautionAlert:W ( D2:W , 0:L ),CC
  256.                     EndIf#
  257.                 EndIf#
  258. DuplicateDrvr:
  259.                 MOVE.L            (SP)+,A0
  260.                 MOVE.W            #openErr,ioResult(A0)
  261.                 Return
  262.                 
  263. DRVRClose        DRVREnter
  264.  
  265.                 MOVE.L            A0,-(SP)
  266.                 MOVE.L            dCtlStorage(A1),A2
  267.                 MOVE.L            (A2),DrvrStorage
  268.  
  269.                 MOVE.L            #ParamBlockSize,D0
  270.                 _NewPtr ,clear
  271.                 MOVE.W            ReadUnit(DrvrStorage),ioRefNum(A0)
  272.                 _Close
  273.                 MOVE.W            WriteUnit(DrvrStorage),ioRefNum(A0)
  274.                 _Close
  275.                 _DisposPtr
  276.                 
  277.                 MOVE.L            KillTask(DrvrStorage),A0
  278.                 _RmvTime
  279.                 _DisposPtr
  280.                 MOVE.L            KillBlock(DrvrStorage),A0
  281.                 _DisposPtr
  282.                 
  283.                 Move.L            A2,A0
  284.                 _DisposHandle
  285.                 
  286.                 MOVE.W            dCtlRefNum(A1),D2
  287.                 Call    _GetNamedResource:L ( #'GNEF':L , #'GNEFilter':A ),A2
  288.                 CMPA            #0,A2
  289.                 If#    NE    Then.S
  290.                     MOVE.L            (A2),A3
  291.                     MOVE.W            Drvr_num(A3),D1
  292.                     If#    D1 GT.W    #1    Then.S
  293.                         While#    D2    NE.W    Drvr_num(A3,D1.W*2) Do.S
  294.                             DBEQ.W            D1,DuplicateClose
  295.                         EndW#
  296.                         If#    D1    NE.W    Drvr_num(A3)    Then.S
  297.                             ADD.W            #1,D1
  298.                             For#    D1    To    Drvr_num(A3)    Do.S
  299.                                 LEA                Drvr_num(A3,D1.W*2),A4
  300.                                 MOVE.W            (A4),-2(A4)
  301.                             EndF#
  302.                         EndIf#
  303.                         SUBQ.W            #1,Drvr_num(A3)
  304.                             
  305.                     ElseIf#.S    D1 EQ.W    #1    Then.S
  306.                         If#    D2    NE.W    Drvrentries(A3)    Then.S
  307.                             GoTo#.S    DuplicateClose
  308.                         EndIf#
  309.                         MOVE.L            GNE_Next(A3),JGNEFilter
  310.                         Call    _ReleaseResource ( A2:L )
  311.                     EndIf#
  312.                 EndIf#
  313. DuplicateClose:                
  314.                 MOVE.W            #noErr,D0
  315.                 MOVE.L            (SP)+,A0
  316.                 
  317.                 DRVRExit        ioTrap(A0)
  318.                 
  319. DRVRPrime        DRVREnter
  320.  
  321.                 MOVE.W        noErr,D0
  322.                 Return
  323.                 
  324.  
  325. DRVRStatus        DRVREnter
  326.  
  327. *  First, check to see if this is an immediate call. If so, it "jumps the line", and will be the
  328. *  next call serviced after the current one (if any) is completed.
  329.  
  330.                 MOVE.W            ioTrap(A0),D1
  331.                 BTST            #noQueueBit,D1
  332.                 If#    NE    Then.S                        ;An Immediate call
  333.                     LEA                dCtlQHead(A1),A2
  334.                     CMP.L            #0,(A2)
  335.                     If#    EQ    Then.S                    ;The queue is empty
  336.                         _Status ,async
  337.                         Return
  338.                     EndIf#
  339.  
  340.                     MOVE.L            (A2),D1
  341.                     CMP.L            4(A2),D1
  342.                     If# EQ Then.S                    ;The queue has only one entry
  343.                         _Status ,async
  344.                         Return
  345.                     EndIf#
  346.                     
  347.                     MOVE.W            ioTrap(A0),D1
  348.                     BCLR            #noQueueBit,D1    ;Fool the driver into thinking this
  349.                     BSET            #asyncTrpBit,D1    ;is an asynchronous queue entry
  350.                     MOVE.W            D1,ioTrap(A0)
  351.                     MOVE.W            #1,ioResult(A0)
  352.  
  353.                     MOVE.L            (A2),A2        ;Get parameter block of queue head
  354.                     MOVE.L            (A2),(A0)    ;Put qLink of qHead in current parameter block
  355.                     MOVE.L            A0,(A2)        ;and replace it with current parameter block pointer
  356.                     Return
  357.                 EndIf#
  358.                     
  359.                 MOVE.L            A0,A2
  360.                 MOVE.L            dCtlStorage(A1),A4
  361.                 MOVE.L            (A4),A4
  362.                 MOVE.L            A1,DCEPtr(A2)
  363.  
  364.                 MOVE.W            TableLen(A4),D1
  365.                 MOVE.W            RequestOffset(A2),D0
  366.                 If#    D0 GT.W D1 Then.S                    ;Not a valid pump call
  367.                     MOVE.W            #statusErr,ioResult(A2)
  368.                     MOVE.L            A2,D0
  369.                     MOVE.W            #app2Evt,A0
  370.                     _PostEvent
  371.                     MOVE.L            A2,A0
  372.                     MOVE.L            #statusErr,D0
  373.                     DRVRExit        ioTrap(A0)
  374.                 EndIf#
  375.  
  376. *  Get some storage for the string we will build
  377.  
  378.                 MOVE.L            #StringAllocation,D0
  379.                 _NewPtr ,clear
  380.                 MOVE.L            A0,A3
  381.  
  382. *  Get some storage for the parameter block that is used for serial driver calls
  383.  
  384.                 MOVE.L            #ParamBlockSize,D0
  385.                 _NewPtr ,clear
  386.                 MOVE.L            A3,ioBuffer(A0)
  387.                 MOVE.L            A2,ioMisc(A0)
  388.             
  389.  
  390. *  Now, get the string formatting info out of the Driver private storage
  391.  
  392.                 MOVE.W            WriteUnit(A4),ioRefNum(A0)
  393.                 MOVE.W            RequestOffset(A2),D0
  394.                 ADD.W            D0,D0
  395.                 Add.W            #TableOffset+2,D0
  396.                 MOVE.L            A0,-(SP)
  397.  
  398.                 If#    ActionOffset(A2) EQ.W #Ask Then.S
  399.                     Call    AskFormat ( A3:L , ioReqCount(A0):A , (A4,D0.W):B )
  400.                 ElseIf#.S    1(A4,D0.W) EQ.B #IntegerFmt Then.S
  401.                     Call    IntegerSet ( A3:L , ioReqCount(A0):A , (A4,D0.W):B ,\
  402.                         InfoOffset(A2):W )
  403.                 Else#.S
  404.                     Call    HexSet ( A3:L , ioReqCount(A0):A , (A4,D0.W):B ,\
  405.                         InfoOffset(A2):W )
  406.                 EndIf#
  407.  
  408.                 MOVE.L            (SP)+,A0
  409.                 LEA                SerialComplete,A3
  410.                 MOVE.L            A3,ioCompletion(A0)
  411.                 _Write ,async
  412.  
  413. *  Set up the time manager task to KillIO on the channel in TimeCount milliseconds. KillBlock
  414. *  is a previously allocated parameter block, which is passed to TimeOutInstall and stored
  415. *  locally (that is, in-line in the code). This is necessary because the routine executes at
  416. *  interrupt level, and is part of a driver, and thus cannot use the memory manager or application
  417. *  globals.
  418.  
  419.                 MOVE.L            KillBlock(A4),A0
  420.                 MOVE.L            WriteUnit(A4),ioRefNum(A0)
  421.                 MOVE.L            KillTask(A4),A0
  422.                 MOVE.L            TimeCount(A4),D0
  423.                 _PrimeTime
  424.                                 
  425.                 MOVE.L            #noErr,D0
  426.                 Return
  427.                                 
  428. DRVRControl        DRVREnter
  429.  
  430.                 If#    csCode(A0)    EQ.W    #accEvent    Then
  431.                     MOVE.L            csParam(A0),A2
  432.                     MOVE.L            myEvent.message(A2),A2
  433.                     MOVE.W            ioTrap(A2),D2
  434.                     AND.W            #$00FF,D2
  435.                     MOVE.W            ioResult(A2),D3
  436.  
  437. *  Check to see the serial call was not aborted by KillIO. If so, inform the application,
  438. *  dequeue the pump driver call, and return
  439.  
  440.                     If#    D3    EQ.W    #abortErr    Then.S
  441.                         MOVE.L            ioMisc(A2),A0
  442.                         EXG                A0,A2
  443.                         _DisposPtr
  444.                         MOVE.W            #TimeOut,ioResult(A2)
  445.                         ADD.W            D2,ioResult(A2)
  446.                         MOVE.L            A2,D0
  447.                         MOVE.W            #app2Evt,A0
  448.                         _PostEvent
  449.                         MOVE.L            #TimeOut,D0
  450.                         MOVE.L            A2,A0
  451.                         DRVRExit        ioTrap(A0)
  452.                     EndIf#
  453.  
  454. *  The serial call did not time out, so figure out if it was a READ or a WRITE by examining
  455. *  the low nybble of the trap field of the parameter block.
  456.  
  457.                     If#    D2    EQ.W    #aRdCmd    Then
  458.  
  459. *  READ - examine the character read. If it is a '*', the new pump is just wasting our valuable
  460. *          time, and so we ignore it and queue another read. If it is a carraige return, we call
  461. *          RespondToRead to interpret the completed pump response. Any other character is 
  462. *          incorporated into the string being built at IncomingString and increment the
  463. *          IncomingLength byte, and another READ is queued. If the byte exceeds 8 characters, we
  464. *          have a problem.
  465.  
  466.                         MOVE.L            ioBuffer(A2),A3
  467.                         MOVE.B            (A3),D1
  468.                         MOVE.L            dCtlStorage(A1),A4
  469.                         MOVE.L            (A4),A4
  470.                         If#    D1    EQ.B    #13    Then.S
  471.                             MOVE.L            KillTask(A4),A0
  472.                             CLR.L            tmCount(A0)
  473.                             MOVE.L            ioMisc(A2),A3
  474.                             Call    RespondToRead
  475.                             MOVE.L            ioMisc(A2),A0
  476.                             EXG                A0,A2
  477.                             _DisposPtr
  478.                             MOVE.L            A2,D0
  479.                             MOVE.W            #app2Evt,A0
  480.                             _PostEvent
  481.                             CLR.B            IncomingLength(A4)
  482.                             CLR.L            IncomingString(A4)
  483.                             CLR.L            IncomingString+4(A4)
  484.                             CLR.L            D0
  485.                             MOVE.L            A2,A0
  486.                             DRVRExit        ioTrap(A0)
  487.                         ElseIf#.S    D1    EQ.B    #'*'    Then.S
  488.                             MOVE.L            A2,A0
  489.                             _Read ,async
  490.                             Return
  491.                         Else#.S
  492.                             MOVE.B            IncomingLength(A4),D0
  493.                             EXT.W            D0
  494.                             MOVE.B            D1,IncomingString(A4,D0.W)
  495.                             ADD.W            #1,D0
  496.                             If#    D0 LE.W    #8 Then.S
  497.                                 MOVE.B            D0,IncomingLength(A4)
  498.                             Else#.S
  499.                                 MOVE.L            KillBlock,A0
  500.                                 MOVE.W            ReadUnit(A4),ioRefNum(A0)
  501.                                 _KillIO
  502.                                 MOVE.L            ioMisc(A2),A0
  503.                                 EXG                A0,A2
  504.                                 _DisposPtr
  505.                                 MOVE.W            #TooManyCharacters,ioResult(A2)
  506.                                 MOVE.L            A2,D0
  507.                                 MOVE.W            #app2Evt,A0
  508.                                 _PostEvent
  509.                                 MOVE.L            A2,A0
  510.                                 MOVE.L            #TooManyCharacters,D0
  511.                                 DRVRExit        ioTrap(A0)
  512.                                 
  513.                             EndIf#
  514.                             MOVE.L            A2,A0
  515.                             _Read ,async
  516.                             Return
  517.                         EndIf#
  518.                     ElseIf#.S    D2    EQ.W    #aWrCmd    Then.S
  519.                         MOVE.L            dCtlStorage(A1),A4
  520.                         MOVE.L            (A4),A4
  521.                         MOVE.L            KillBlock(A4),A0
  522.                         MOVE.W            ReadUnit(A4),ioRefNum(A0)
  523.                         MOVE.L            A2,A0
  524.                         MOVE.W            ReadUnit(A4),ioRefNum(A0)
  525.                         MOVE.L            #1,ioReqCount(A0)
  526.                         MOVE.L            ioBuffer(A0),A2
  527.                         LEA                ReadBuffer(A2),A2
  528.                         MOVE.L            A2,ioBuffer(A0)
  529.                         LEA                SerialComplete,A4
  530.                         MOVE.L            A4,ioCompletion(A0)
  531.                         _Read ,async
  532.                         Return
  533.                     EndIf#
  534.                 ElseIf#.S    csCode(A0)    EQ.W    #accRun    Then.S
  535.                     MOVE.L            A0,-(SP)
  536.                     MOVE.L            #ParamBlockSize,D0
  537.                     _NewPtr ,clear
  538.                     MOVE.W            dCtlRefNum(A1),ioRefNum(A0)
  539.                     MOVE.W            #S_request,RequestOffset(A0)
  540.                     MOVE.W            #Ask,ActionOffset(A0)
  541.                     CLR.L            ioCompletion(A0)
  542.                     _Status ,async
  543.                     MOVE.L            (SP)+,A0
  544.  
  545.                 ElseIf#.S    csCode(A0)    EQ.W    #killCode    Then.S
  546.                     
  547.                     MOVE.L            #ParamBlockSize,D0
  548.                     MOVE.L            dCtlStorage(A1),A2
  549.                     MOVE.L            (A2),A2
  550.                     _NewPtr ,clear
  551.                     MOVE.W            ReadUnit(A2),ioRefNum(A0)
  552.                     _KillIO
  553.                     MOVE.W            WriteUnit(A2),ioRefNum(A0)
  554.                     _KillIO
  555.                     _DisposPtr
  556.                     Return
  557.                     
  558.                 ElseIf#.S    csCode(A0)    EQ.W    #goodBye    Then.S
  559.                     JMP                DRVRClose
  560.                 EndIf#
  561.  
  562.                 MOVE.L            #noErr,D0
  563.                 DRVRExit        ioTrap(A0)
  564.                 
  565.                 ENDP
  566.  
  567.                 END
  568.